From 99e957075c73ba2c21dd4d2d37786a07d9966134 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 24 Jan 2006 18:05:45 +0100 Subject: [PATCH] Indirect hypercalls through a hypercall transfer page. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/entry.S | 6 +-- .../arch/xen/i386/kernel/head.S | 4 ++ .../arch/xen/x86_64/kernel/entry.S | 13 ++--- .../arch/xen/x86_64/kernel/head.S | 12 +++-- .../drivers/xen/privcmd/privcmd.c | 11 ++-- .../include/asm-xen/asm-i386/hypercall.h | 36 ++++++------- .../include/asm-xen/asm-x86_64/hypercall.h | 50 +++++++++---------- tools/libxc/xc_linux_build.c | 18 ++++++- tools/libxc/xc_load_elf.c | 3 ++ tools/libxc/xg_private.h | 3 ++ xen/arch/x86/dom0_ops.c | 32 ++++++++++-- xen/arch/x86/domain_build.c | 22 +++++++- xen/arch/x86/x86_32/traps.c | 27 ++++++++++ xen/arch/x86/x86_64/traps.c | 33 ++++++++++++ xen/include/asm-x86/domain.h | 6 +++ xen/include/public/dom0_ops.h | 7 +++ 16 files changed, 215 insertions(+), 68 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S b/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S index ef23e7ca3c..6c43b26aab 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S @@ -333,10 +333,8 @@ iret_exc: hypervisor_iret: andl $~NMI_MASK, EFLAGS(%esp) RESTORE_REGS - movl %eax,(%esp) - movl $__HYPERVISOR_iret,%eax - int $0x82 - ud2 + addl $4, %esp + jmp hypercall_page + (__HYPERVISOR_iret * 32) #if 0 /* XEN */ ldt_ss: diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/head.S b/linux-2.6-xen-sparse/arch/xen/i386/kernel/head.S index 220cf8fd7a..b59c542101 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/head.S +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/head.S @@ -5,6 +5,7 @@ .ascii "GUEST_OS=linux,GUEST_VER=2.6" .ascii ",XEN_VER=xen-3.0" .ascii ",VIRT_BASE=0xC0000000" + .ascii ",HYPERCALL_PAGE=0x104" /* __pa(hypercall_page) >> 12 */ #ifdef CONFIG_X86_PAE .ascii ",PAE=yes" #else @@ -187,6 +188,9 @@ ENTRY(cpu_gdt_table) ENTRY(default_ldt) .org 0x4000 +ENTRY(hypercall_page) + +.org 0x5000 /* * Real beginning of normal "text" segment */ diff --git a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S index 2fbe90706c..0e28067165 100644 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S @@ -127,15 +127,10 @@ * }; * #define VGCF_IN_SYSCALL (1<<8) */ - .macro HYPERVISOR_IRET flag - subq $8*4,%rsp # reuse rip, cs, rflags, rsp, ss in the stack - movq %rax,(%rsp) - movq %r11,1*8(%rsp) - movq %rcx,2*8(%rsp) # we saved %rcx upon exceptions - movq $\flag,3*8(%rsp) - movq $__HYPERVISOR_iret,%rax - syscall - .endm + .macro HYPERVISOR_IRET flag + pushq $\flag + jmp hypercall_page + (__HYPERVISOR_iret * 32) + .endm .macro SWITCH_TO_KERNEL ssoff,adjust=0 jc 1f diff --git a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/head.S b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/head.S index c22996e8e4..12f96941e3 100644 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/head.S +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/head.S @@ -16,9 +16,11 @@ #include .section __xen_guest - .ascii "GUEST_OS=linux,GUEST_VER=2.6,XEN_VER=xen-3.0,VIRT_BASE=0xffffffff80000000" + .ascii "GUEST_OS=linux,GUEST_VER=2.6" + .ascii ",XEN_VER=xen-3.0" + .ascii ",VIRT_BASE=0xffffffff80000000" + .ascii ",HYPERCALL_PAGE=0x10d" /* __pa(hypercall_page) >> 12 */ .ascii ",LOADER=generic" -/* .ascii ",PT_MODE_WRITABLE" */ .byte 0 @@ -227,8 +229,10 @@ ENTRY(empty_bad_pmd_table) ENTRY(level3_physmem_pgt) .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */ - - .org 0xd000 +.org 0xd000 +ENTRY(hypercall_page) + +.org 0xe000 #ifdef CONFIG_ACPI_SLEEP ENTRY(wakeup_level4_pgt) .quad 0x0000000000102007 /* -> level3_ident_pgt */ diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index 107f3e8bef..a4a533aa6b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -58,7 +58,9 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, "movl 16(%%eax),%%esi ;" "movl 20(%%eax),%%edi ;" "movl (%%eax),%%eax ;" - TRAP_INSTR "; " + "shll $5,%%eax ;" + "addl $hypercall_page,%%eax ;" + "call *%%eax ;" "popl %%edi; popl %%esi; popl %%edx; " "popl %%ecx; popl %%ebx" : "=a" (ret) : "0" (&hypercall) : "memory" ); @@ -66,7 +68,10 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, { long ign1, ign2, ign3; __asm__ __volatile__ ( - "movq %8,%%r10; movq %9,%%r8;" TRAP_INSTR + "movq %8,%%r10; movq %9,%%r8;" + "shlq $5,%%rax ;" + "addq $hypercall_page,%%rax ;" + "call *%%rax" : "=a" (ret), "=D" (ign1), "=S" (ign2), "=d" (ign3) : "0" ((unsigned long)hypercall.op), @@ -75,7 +80,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, "3" ((unsigned long)hypercall.arg[2]), "g" ((unsigned long)hypercall.arg[3]), "g" ((unsigned long)hypercall.arg[4]) - : "r11","rcx","r8","r10","memory"); + : "r8", "r10", "memory" ); } #elif defined (__ia64__) __asm__ __volatile__ ( diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h index 04edbd3741..b81ea36cb4 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h @@ -34,13 +34,15 @@ #include #include +#define __STR(x) #x +#define STR(x) __STR(x) + #define _hypercall0(type, name) \ ({ \ long __res; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res) \ - : "0" (__HYPERVISOR_##name) \ : "memory" ); \ (type)__res; \ }) @@ -49,9 +51,9 @@ ({ \ long __res, __ign1; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=b" (__ign1) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)) \ + : "1" ((long)(a1)) \ : "memory" ); \ (type)__res; \ }) @@ -60,10 +62,9 @@ ({ \ long __res, __ign1, __ign2; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)) \ + : "1" ((long)(a1)), "2" ((long)(a2)) \ : "memory" ); \ (type)__res; \ }) @@ -72,11 +73,11 @@ ({ \ long __res, __ign1, __ign2, __ign3; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ "=d" (__ign3) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)) \ : "memory" ); \ (type)__res; \ }) @@ -85,12 +86,11 @@ ({ \ long __res, __ign1, __ign2, __ign3, __ign4; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ "=d" (__ign3), "=S" (__ign4) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)), \ - "4" ((long)(a4)) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)) \ : "memory" ); \ (type)__res; \ }) @@ -99,12 +99,12 @@ ({ \ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)), \ - "4" ((long)(a4)), "5" ((long)(a5)) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)), \ + "5" ((long)(a5)) \ : "memory" ); \ (type)__res; \ }) diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h index 521f004c00..840cdb8f7a 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h @@ -37,16 +37,16 @@ #include #include -#define __syscall_clobber "r11","rcx","memory" +#define __STR(x) #x +#define STR(x) __STR(x) #define _hypercall0(type, name) \ ({ \ long __res; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res) \ - : "0" (__HYPERVISOR_##name) \ - : __syscall_clobber ); \ + : "memory" ); \ (type)__res; \ }) @@ -54,10 +54,10 @@ ({ \ long __res, __ign1; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=D" (__ign1) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)) \ - : __syscall_clobber ); \ + : "1" ((long)(a1)) \ + : "memory" ); \ (type)__res; \ }) @@ -65,11 +65,10 @@ ({ \ long __res, __ign1, __ign2; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=D" (__ign1), "=S" (__ign2) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)) \ - : __syscall_clobber ); \ + : "1" ((long)(a1)), "2" ((long)(a2)) \ + : "memory" ); \ (type)__res; \ }) @@ -77,12 +76,12 @@ ({ \ long __res, __ign1, __ign2, __ign3; \ asm volatile ( \ - TRAP_INSTR \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ "=d" (__ign3) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)) \ - : __syscall_clobber ); \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)) \ + : "memory" ); \ (type)__res; \ }) @@ -90,13 +89,13 @@ ({ \ long __res, __ign1, __ign2, __ign3; \ asm volatile ( \ - "movq %8,%%r10; " TRAP_INSTR \ + "movq %8,%%r10; " \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ "=d" (__ign3) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)), \ - "g" ((long)(a4)) \ - : __syscall_clobber, "r10" ); \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "g" ((long)(a4)) \ + : "memory", "r10" ); \ (type)__res; \ }) @@ -104,13 +103,14 @@ ({ \ long __res, __ign1, __ign2, __ign3; \ asm volatile ( \ - "movq %8,%%r10; movq %9,%%r8; " TRAP_INSTR \ + "movq %8,%%r10; movq %9,%%r8; " \ + "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ "=d" (__ign3) \ - : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ - "2" ((long)(a2)), "3" ((long)(a3)), \ - "g" ((long)(a4)), "g" ((long)(a5)) \ - : __syscall_clobber, "r10", "r8" ); \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "g" ((long)(a4)), \ + "g" ((long)(a5)) \ + : "memory", "r10", "r8" ); \ (type)__res; \ }) diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 23fc456554..6e18994530 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -429,10 +429,12 @@ static int setup_guest(int xc_handle, unsigned int console_evtchn, unsigned long *console_mfn) { unsigned long *page_array = NULL; - unsigned long count, i; + unsigned long count, i, hypercall_pfn; start_info_t *start_info; shared_info_t *shared_info; xc_mmu_t *mmu = NULL; + char *p; + DECLARE_DOM0_OP; int rc; unsigned long nr_pt_pages; @@ -715,6 +717,20 @@ static int setup_guest(int xc_handle, if ( xc_finish_mmu_updates(xc_handle, mmu) ) goto error_out; + p = strstr(dsi.xen_guest_string, "HYPERCALL_PAGE="); + if ( p != NULL ) + { + p += strlen("HYPERCALL_PAGE="); + hypercall_pfn = strtoul(p, NULL, 16); + if ( hypercall_pfn >= nr_pages ) + goto error_out; + op.u.hypercall_init.domain = (domid_t)dom; + op.u.hypercall_init.mfn = page_array[hypercall_pfn]; + op.cmd = DOM0_HYPERCALL_INIT; + if ( xc_dom0_op(xc_handle, &op) ) + goto error_out; + } + free(mmu); free(page_array); diff --git a/tools/libxc/xc_load_elf.c b/tools/libxc/xc_load_elf.c index ac8fb81ccc..b1fc2af4c0 100644 --- a/tools/libxc/xc_load_elf.c +++ b/tools/libxc/xc_load_elf.c @@ -120,6 +120,7 @@ static int parseelfimage(char *image, break; } + if ( guestinfo == NULL ) { #ifdef __ia64__ @@ -130,6 +131,8 @@ static int parseelfimage(char *image, #endif } + dsi->xen_guest_string = guestinfo; + for ( h = 0; h < ehdr->e_phnum; h++ ) { phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize)); diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h index f96c187d95..755c682896 100644 --- a/tools/libxc/xg_private.h +++ b/tools/libxc/xg_private.h @@ -136,6 +136,9 @@ struct domain_setup_info unsigned int pae_kernel; unsigned long symtab_addr; unsigned long symtab_len; + + /* __xen_guest info string for convenient loader parsing. */ + char *xen_guest_string; }; typedef int (*parseimagefunc)(char *image, unsigned long image_size, diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 1ee7efd37b..848d7f000e 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -50,9 +50,6 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) { long ret = 0; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - switch ( op->cmd ) { @@ -409,6 +406,35 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) } break; + case DOM0_HYPERCALL_INIT: + { + struct domain *d; + unsigned long mfn = op->u.hypercall_init.mfn; + void *hypercall_page; + + ret = -ESRCH; + if ( unlikely((d = find_domain_by_id( + op->u.hypercall_init.domain)) == NULL) ) + break; + + ret = -EACCES; + if ( !pfn_valid(mfn) || + !get_page_and_type(pfn_to_page(mfn), d, PGT_writable_page) ) + { + put_domain(d); + break; + } + + ret = 0; + + hypercall_page = map_domain_page(mfn); + hypercall_page_initialise(hypercall_page); + unmap_domain_page(hypercall_page); + + put_domain(d); + } + break; + default: ret = -ENOSYS; break; diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 84d84a66cf..bf394416a8 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -146,6 +146,8 @@ int construct_dom0(struct domain *d, struct pfn_info *page = NULL; start_info_t *si; struct vcpu *v = d->vcpu[0]; + char *p; + unsigned long hypercall_page; #if defined(__i386__) char *image_start = (char *)_image_start; /* use lowmem mappings */ char *initrd_start = (char *)_initrd_start; /* use lowmem mappings */ @@ -239,7 +241,8 @@ int construct_dom0(struct domain *d, xen_pae ? "yes" : "no", dom0_pae ? "yes" : "no"); return -EINVAL; } - if (strstr(dsi.xen_section_string, "SHADOW=translate")) + + if ( strstr(dsi.xen_section_string, "SHADOW=translate") ) opt_dom0_translate = 1; /* Align load address to 4MB boundary. */ @@ -604,6 +607,23 @@ int construct_dom0(struct domain *d, /* Copy the OS image and free temporary buffer. */ (void)loadelfimage(&dsi); + p = strstr(dsi.xen_section_string, "HYPERCALL_PAGE="); + if ( p != NULL ) + { + p += strlen("HYPERCALL_PAGE="); + hypercall_page = simple_strtoul(p, NULL, 16); + hypercall_page = dsi.v_start + (hypercall_page << PAGE_SHIFT); + if ( (hypercall_page < dsi.v_start) || (hypercall_page >= v_end) ) + { + write_ptbase(current); + local_irq_enable(); + printk("Invalid HYPERCALL_PAGE field in guest header.\n"); + return -1; + } + + hypercall_page_initialise((void *)hypercall_page); + } + init_domheap_pages( _image_start, (_image_start+image_len+PAGE_SIZE-1) & PAGE_MASK); diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 95b69a14bd..587287d0bb 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -298,6 +298,33 @@ long do_set_callbacks(unsigned long event_selector, return 0; } +void hypercall_page_initialise(void *hypercall_page) +{ + char *p; + int i; + + /* Fill in all the transfer points with template machine code. */ + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p+ 0) = 0xb8; /* mov $,%eax */ + *(u32 *)(p+ 1) = i; + *(u16 *)(p+ 5) = 0x82cd; /* int $0x82 */ + *(u8 *)(p+ 7) = 0xc3; /* ret */ + } + + /* + * HYPERVISOR_iret is special because it doesn't return and expects a + * special stack frame. Guests jump at this transfer point instead of + * calling it. + */ + p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); + *(u8 *)(p+ 0) = 0x50; /* push %eax */ + *(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */ + *(u32 *)(p+ 2) = __HYPERVISOR_iret; + *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */ +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 9756c54589..ebf364cf8c 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -268,6 +268,39 @@ long do_set_callbacks(unsigned long event_address, return 0; } +void hypercall_page_initialise(void *hypercall_page) +{ + char *p; + int i; + + /* Fill in all the transfer points with template machine code. */ + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p+ 0) = 0x51; /* push %rcx */ + *(u16 *)(p+ 1) = 0x5341; /* push %r11 */ + *(u8 *)(p+ 3) = 0xb8; /* mov $,%eax */ + *(u32 *)(p+ 4) = i; + *(u16 *)(p+ 8) = 0x050f; /* syscall */ + *(u16 *)(p+10) = 0x5b41; /* pop %r11 */ + *(u8 *)(p+12) = 0x59; /* pop %rcx */ + *(u8 *)(p+13) = 0xc3; /* ret */ + } + + /* + * HYPERVISOR_iret is special because it doesn't return and expects a + * special stack frame. Guests jump at this transfer point instead of + * calling it. + */ + p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); + *(u8 *)(p+ 0) = 0x50; /* push %rax */ + *(u8 *)(p+ 1) = 0x51; /* push %rcx */ + *(u16 *)(p+ 2) = 0x5341; /* push %r11 */ + *(u8 *)(p+ 4) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */ + *(u32 *)(p+ 5) = __HYPERVISOR_iret; + *(u16 *)(p+ 9) = 0x050f; /* syscall */ +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 6438757d67..687dce5a30 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -51,6 +51,12 @@ extern void mapcache_init(struct domain *); /* x86/64: toggle guest between kernel and user modes. */ extern void toggle_guest_mode(struct vcpu *); +/* + * Initialise a hypercall-transfer page. The given pointer must be mapped + * in Xen virtual address space (accesses are not validated or checked). + */ +extern void hypercall_page_initialise(void *); + struct arch_domain { l1_pgentry_t *mm_perdomain_pt; diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 9e59e771b1..4a70a77e49 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -425,6 +425,12 @@ typedef struct { uint8_t allow_access; /* allow (!0) or deny (0) access to range? */ } dom0_iomem_permission_t; +#define DOM0_HYPERCALL_INIT 48 +typedef struct { + domid_t domain; /* domain to be affected */ + unsigned long mfn; /* machine frame to be initialised */ +} dom0_hypercall_init_t; + typedef struct { uint32_t cmd; uint32_t interface_version; /* DOM0_INTERFACE_VERSION */ @@ -465,6 +471,7 @@ typedef struct { dom0_setdebugging_t setdebugging; dom0_irq_permission_t irq_permission; dom0_iomem_permission_t iomem_permission; + dom0_hypercall_init_t hypercall_init; uint8_t pad[128]; } u; } dom0_op_t; -- 2.30.2